package org.l.qiao.util;

import org.apache.log4j.Logger;
import org.l.qiao.Cluster;
import org.l.qiao.KeyType;
import org.l.qiao.Validate;
import org.l.qiao.annotation.Key;
import org.l.qiao.base.Convert;
import org.l.qiao.base.UnknowLTypeException;
import org.l.qiao.el.UnsupportObjectException;

import java.lang.reflect.Field;
import java.util.*;


/**
 * Created by 严秋旺 on 2015/1/14.
 */
public class ClusterUtil {
    private static final Logger LOGGER = Logger.getLogger(ClusterUtil.class);

    /**
     * EL表达式键名分割符
     */
    private static final String ELKEY_SEPARATOR_REGEX = "\\.";
    /**
     * EL表达式分割符
     */
    public static final char ELKEY_SEPARATOR_CHAR = '.';

    /**
     * 根据el表达式获取Map对象里的值
     *
     * @param map   待取值对象
     * @param elKey el表达式
     * @return el表达式对应的值，不存在则返回null
     */
    public static Object get(Map map, String elKey) {
        if (elKey == null) {
            throw new NullPointerException("el表达式不能是空值");
        }

        String[] keys = elKey.split(ELKEY_SEPARATOR_REGEX);
        Object object = map;

        for (int i = 0; i < keys.length; i++) {
            if (object == null) {
                break;
            } else if (object instanceof List) {
                int index = Integer.parseInt(keys[i]);
                List list = (List) object;
                object = list.get(index);
            } else if (object instanceof Map) {
                Map tempMap = (Map) object;
                object = tempMap.get(keys[i]);
            } else {
                throw new UnsupportObjectException("不支持操作对象", object);
            }
        }

        return object;
    }

    /**
     * 根据el表达式获取值，路径上如果是空对象则补充HashMap对象，最后一级如果为空则设置指定默认值
     *
     * @param map   Map对象
     * @param elKey el表达式
     * @return el表达式所对应的值
     */
    private static Object getAndFill(Map map, String elKey) {
        String[] keys = elKey.split(ELKEY_SEPARATOR_REGEX);
        Object object = map;

        for (int i = 0; i < keys.length; i++) {
            if (object instanceof List) {
                int index = Integer.parseInt(keys[i]);
                List list = (List) object;

                if (list.size() <= index) {
                    enlange(list, index + 1);
                }

                object = list.get(index);

                if (object == null) {
                    object = new HashMap();
                    list.set(index, object);
                }
            } else if (object instanceof Map) {
                Map tempMap = (Map) object;
                object = tempMap.get(keys[i]);

                if (object == null) {
                    object = new HashMap();
                    tempMap.put(keys[i], object);
                }

            } else {
                throw new UnsupportObjectException("不支持操作对象", object);
            }
        }

        return object;
    }

    /**
     * 获取el表达式的父级el表达式
     *
     * @param elKey el表达式
     * @return 父级el表达式
     */
    public static String parent(String elKey) {
        int lastIndex = elKey.lastIndexOf(ELKEY_SEPARATOR_CHAR);

        if (lastIndex > 0) {
            return elKey.substring(0, lastIndex);
        } else {
            return elKey;
        }
    }

    /**
     * 获取el表达式的叶子节点
     *
     * @param elKey
     * @return
     */
    public static String leaf(String elKey) {
        int lastIndex = elKey.lastIndexOf(ELKEY_SEPARATOR_CHAR);

        if (lastIndex > 0) {
            return elKey.substring(lastIndex + 1);
        } else {
            return elKey;
        }
    }

    /**
     * 根据el表达式设置map对象值
     *
     * @param map   map对象
     * @param elKey el表达式
     * @param value 设置的值
     * @return el表达式对应的旧值
     */
    public static Object put(Map map, String elKey, Object value) {
        if (elKey == null) {
            throw new NullPointerException("el表达式不能是空值");
        }

        String parentELKey = parent(elKey);
        String leafKey;
        Object object, oldvalue;

        if (elKey.equals(parentELKey)) {
            leafKey = elKey;
            object = map;
        } else {
            leafKey = leaf(elKey);
            object = getAndFill(map, parentELKey);
        }

        if (object instanceof List) {
            oldvalue = listSet(object, leafKey, value);
        } else if (object instanceof Map) {
            oldvalue = ((Map) object).put(leafKey, value);
        } else {
            throw new UnsupportObjectException("不支持操作对象", object);
        }

        return oldvalue;
    }

    /**
     * 对el表达式指定的列表添加元素
     *
     * @param map   map对象
     * @param elKey el表达式
     * @param value 添加的元素
     * @return
     */
    public static boolean add(Map map, String elKey, Object value) {
        if (elKey == null) {
            throw new NullPointerException("el表达式不能是空值");
        }

        String parentELKey = parent(elKey);
        String leafKey;
        Object object;

        if (elKey.equals(parentELKey)) {
            leafKey = elKey;
            object = map;
        } else {
            leafKey = leaf(elKey);
            object = getAndFill(map, parentELKey);
        }

        if (object instanceof List) {
            List tempList = (List) object;
            int index = Integer.parseInt(leafKey);
            object = tempList.get(index);

            if (object == null) {
                object = new ArrayList();
                listSet(tempList, leafKey, object);
            }

        } else if (object instanceof Map) {
            Map tempMap = (Map) object;
            object = tempMap.get(leafKey);

            if (object == null) {
                object = new ArrayList();
                tempMap.put(leafKey, object);
            }

        } else {
            throw new UnsupportObjectException("不支持操作对象", object);
        }

        if (object instanceof List) {
            List list = (List) object;
            return list.add(value);
        } else {
            throw new UnsupportObjectException("非List类型对象，无法添加元素", object);
        }

    }

    /**
     * 数组对象设置值，当序列号超出数组大小时扩大数组
     *
     * @param object   数组对象
     * @param indexStr 序列号
     * @param value    值
     * @return 旧的值
     */
    private static Object listSet(Object object, String indexStr, Object value) {
        List list = (List) object;
        int index = Integer.parseInt(indexStr);

        if (list.size() <= index) {
            enlange(list, index + 1);
        }

        Object oldvalue = list.get(index);
        list.set(index, value);
        return oldvalue;
    }

    /**
     * 扩大数组列表
     *
     * @param list    被扩大列表
     * @param dstSize 目标列表大小
     */
    public static void enlange(List list, int dstSize) {
        for (int i = list.size(); i < dstSize; i++) {
            list.add(null);
        }
    }

    public static void put(Cluster cluster, String keyPath, KeyType keyType, Object value) {
        switch (keyType) {
            case ListKey:
                add(cluster, keyPath, value);
                break;
            default:
                put(cluster, keyPath, value);
        }
    }

    /**
     * 获取数据簇的检查对象
     *
     * @param clusterClass 数据簇
     * @return 返回各键值的检查对象集合
     */
    public static Cluster getCheck(Class clusterClass) {
        Cluster checkMap = new Cluster();
        Field[] fields = clusterClass.getFields();
        for (Field field : fields) {
            Key annotation = field.getAnnotation(Key.class);
            if (annotation != null) {
                try {
                    checkMap.put(field.get(null).toString(), annotation.check());
                } catch (IllegalAccessException e) {
                    LOGGER.error("键值获取异常[" + field.getName() + "]：" + e);
                }
            }
        }
        return checkMap;
    }

    public static void extend(Map source, Map map) {
        Iterator iterator = map.entrySet().iterator();

        while (iterator.hasNext()) {
            Map.Entry entry = (Map.Entry) iterator.next();
            Object key = entry.getKey();
            Object src = source.get(entry.getKey());
            Object dest = entry.getValue();

            if (dest instanceof Map && src instanceof Map) {
                extend((Map) src, (Map) dest);
            } else {
                source.put(key, dest);
            }

        }
    }

    public static Map<String, Key> keys(Class clazz) {
        Map<String, Key> keys = new HashMap();
        Field[] fields = clazz.getFields();

        for (Field field : fields) {
            Key annotation = field.getAnnotation(Key.class);

            if (annotation == null) {
                continue;
            }

            try {
                String keyPath = String.valueOf(field.get(clazz));

                if (!keys.containsKey(keyPath)) {
                    keys.put(keyPath, annotation);
                }
            } catch (IllegalAccessException e) {
                LOGGER.debug("键值获取失败：" + field.getName());
            }

        }

        return keys;
    }

}
